package com.j.thetabk;

import android.mtp.MtpConstants;
import android.mtp.MtpDevice;
import android.mtp.MtpObjectInfo;
import android.os.Environment;
import android.os.StatFs;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.UUID;

/**
 * Created by jhanbin on 16/8/2016.
 */
public class MTPTransfer {


    public interface MTPTransferUpdate
    {
        void OnUpdate(MtpObjectInfo mtpObjectInfo, int status);
        void TrackFile(String path, long size, boolean bMove);

        void UpdateFile(String path, long size, int status);
        void UpdateTotal(long count, long size);
    }

    public static String RandStr()
    {
        return UUID.randomUUID().toString().substring(0,8);
    }

    public static boolean AutoRename(String fp)
    {
        File file=new File(fp);
        if(file.exists())
        {
            int segidx=fp.lastIndexOf(".");
            File newfile= new File(fp.substring(0,segidx)+"_"+RandStr()+fp.substring(segidx,fp.length()));
            while(newfile.exists())
            {
                newfile= new File(fp.substring(0,segidx)+"_"+RandStr()+fp.substring(segidx,fp.length()));
            }
            return file.renameTo(newfile);
        }
        return false;
    }

    public static String SizeStr(long size)
    {
        if(size<1024)
            return size+"B";
        size/=1024;
        if(size<1024)
            return size+"KB";
        size/=1024;
        if(size<1024)
            return size+"MB";
        size/=1024;
        return size+"GB";
    }


    public static int countObjectsInStorage(MtpDevice mtpDevice, int storageId, int format, int parent, int []selectType)
    {
        int[] objectHandles = mtpDevice.getObjectHandles(storageId, format, parent);

        if (objectHandles == null)
            return 0;

        int count=0;
        for (int objectHandle : objectHandles)
        {
            MtpObjectInfo mtpObjectInfo = mtpDevice.getObjectInfo(objectHandle);
            if (mtpObjectInfo == null)
                continue;
            int parentOfObject = mtpObjectInfo.getParent();
            if (parentOfObject != parent)
                continue;

            int associationType = mtpObjectInfo.getAssociationType();

            if (associationType == MtpConstants.ASSOCIATION_TYPE_GENERIC_FOLDER)
            {
                count+=countObjectsInStorage(mtpDevice, storageId, format, objectHandle, selectType);
                continue;
            }

            int status=mtpObjectInfo.getProtectionStatus();

            if(status == MtpConstants.PROTECTION_STATUS_NON_TRANSFERABLE_DATA)
                continue;

            int objFormat=mtpObjectInfo.getFormat();

            if(CheckType(objFormat, selectType))
                count++;
        }
        return count;

    }

    public static long[] countObjectsInStorage2(MtpDevice mtpDevice, int storageId, int format, int parent, int []selectType)
    {
        int[] objectHandles = mtpDevice.getObjectHandles(storageId, format, parent);

        if (objectHandles == null)
            return new long[]{0,0};

        long count=0;
        long size=0;
        for (int objectHandle : objectHandles)
        {
            MtpObjectInfo mtpObjectInfo = mtpDevice.getObjectInfo(objectHandle);
            if (mtpObjectInfo == null)
                continue;
            int parentOfObject = mtpObjectInfo.getParent();
            if (parentOfObject != parent)
                continue;

            int associationType = mtpObjectInfo.getAssociationType();

            if (associationType == MtpConstants.ASSOCIATION_TYPE_GENERIC_FOLDER)
            {
                long []res=countObjectsInStorage2(mtpDevice, storageId, format, objectHandle, selectType);
                count+=res[0];
                size+=res[1];
                continue;
            }

            int status=mtpObjectInfo.getProtectionStatus();

            if(status == MtpConstants.PROTECTION_STATUS_NON_TRANSFERABLE_DATA)
                continue;

            int objFormat=mtpObjectInfo.getFormat();

            if(CheckType(objFormat, selectType))
            {
                count++;
                size+=GetMtpObjectBytes(mtpObjectInfo);
            }

        }
        return new long[]{count,size};

    }



    public static boolean CheckType(int format, int []selectType)
    {
        for(int st:selectType)
            if(format==st)
                return true;
        return false;
    }

    public static void scanObjectsInStorage(MtpDevice mtpDevice, int storageId, int format, int parent,
                                            String parentFolder, boolean bMove, int []selectType, MTPTransferUpdate mtpUpdate)
    {
        int[] objectHandles = mtpDevice.getObjectHandles(storageId, format, parent);

        if (objectHandles == null)
            return;

        for (int objectHandle : objectHandles)
        {
            MtpObjectInfo mtpObjectInfo = mtpDevice.getObjectInfo(objectHandle);
            if (mtpObjectInfo == null)
                continue;
            int parentOfObject = mtpObjectInfo.getParent();
            if (parentOfObject != parent)
                continue;

            int associationType = mtpObjectInfo.getAssociationType();

            if (associationType == MtpConstants.ASSOCIATION_TYPE_GENERIC_FOLDER)
            {
                String subfolder=mtpObjectInfo.getName();
                File d=new File(parentFolder+"/"+subfolder);
                if(d.exists()) {
                    scanObjectsInStorage(mtpDevice, storageId, format, objectHandle, parentFolder + "/" + subfolder, bMove, selectType, mtpUpdate);
                    continue;
                }
                if(d.mkdir()){
                    scanObjectsInStorage(mtpDevice, storageId, format, objectHandle, parentFolder+"/"+subfolder, bMove, selectType, mtpUpdate);
                }
                continue;
            }

            int status=mtpObjectInfo.getProtectionStatus();

            if(status == MtpConstants.PROTECTION_STATUS_NON_TRANSFERABLE_DATA)
                continue;

            int objFormat=mtpObjectInfo.getFormat();

            if(CheckType(objFormat, selectType))
            {
                long fsize=GetMtpObjectBytes(mtpObjectInfo);
                if(fsize>GetSDCardBytes()[0])
                {
                    if(mtpUpdate!=null) mtpUpdate.OnUpdate(mtpObjectInfo, 3);
                    continue;
                }

                if(mtpUpdate!=null) mtpUpdate.OnUpdate(mtpObjectInfo, 0);

                String filename=mtpObjectInfo.getName();
                AutoRename(parentFolder+"/"+filename);

                if(fsize>10*1024*1024)
                    if(mtpUpdate!=null) mtpUpdate.TrackFile(parentFolder+"/"+filename, fsize, bMove);

                if(mtpDevice.importFile(objectHandle, parentFolder+"/"+filename))
                {
                    if(mtpUpdate!=null) mtpUpdate.OnUpdate(mtpObjectInfo, 1);
                    if(bMove)
                        mtpDevice.deleteObject(objectHandle);
                }
                else
                {
                    if(mtpUpdate!=null) mtpUpdate.OnUpdate(mtpObjectInfo, 2);
                }
            }
        }
    }

    public static void scanObjectsInStorage2(MtpDevice mtpDevice, int storageId, int format, int parent,
                                             String parentFolder, boolean bMove, int []selectType, MTPTransferUpdate mtpUpdate)
    {
        int[] objectHandles = mtpDevice.getObjectHandles(storageId, format, parent);

        if (objectHandles == null)
            return;

        for (int objectHandle : objectHandles)
        {
            MtpObjectInfo mtpObjectInfo = mtpDevice.getObjectInfo(objectHandle);
            if (mtpObjectInfo == null)
                continue;
            int parentOfObject = mtpObjectInfo.getParent();
            if (parentOfObject != parent)
                continue;

            int associationType = mtpObjectInfo.getAssociationType();

            if (associationType == MtpConstants.ASSOCIATION_TYPE_GENERIC_FOLDER)
            {
                String subfolder=mtpObjectInfo.getName();
                File d=new File(parentFolder+"/"+subfolder);
                if(d.exists()) {
                    scanObjectsInStorage2(mtpDevice, storageId, format, objectHandle, parentFolder + "/" + subfolder, bMove, selectType, mtpUpdate);
                    continue;
                }
                if(d.mkdir()){
                    scanObjectsInStorage2(mtpDevice, storageId, format, objectHandle, parentFolder+"/"+subfolder, bMove, selectType, mtpUpdate);
                }
                continue;
            }

            int status=mtpObjectInfo.getProtectionStatus();

            if(status == MtpConstants.PROTECTION_STATUS_NON_TRANSFERABLE_DATA)
                continue;

            int objFormat=mtpObjectInfo.getFormat();

            if(CheckType(objFormat, selectType))
            {
                long fsize=GetMtpObjectBytes(mtpObjectInfo);

                String filename=mtpObjectInfo.getName();

                if(fsize>GetSDCardBytes()[0])
                {
                    if(mtpUpdate!=null) mtpUpdate.UpdateFile(parentFolder+"/"+filename, fsize, 3);
                    continue;
                }

                if(mtpUpdate!=null) mtpUpdate.UpdateFile(parentFolder+"/"+filename, fsize, 0);

                AutoRename(parentFolder+"/"+filename);

                if(mtpDevice.importFile(objectHandle, parentFolder+"/"+filename))
                {
                    if(mtpUpdate!=null) mtpUpdate.UpdateFile(parentFolder+"/"+filename, fsize, 1);
                    if(bMove)
                        mtpDevice.deleteObject(objectHandle);
                }
                else
                {
                    if(mtpUpdate!=null) mtpUpdate.UpdateFile(parentFolder+"/"+filename, fsize, 2);
                }
            }
        }
    }



    public static int ScanTransfer(MtpDevice mtpDevice, String folder, boolean bMove, int []selectType, MTPTransferUpdate mtpUpdate)
    {
        if(!(new File(folder).exists()))
            return 1;
        if(selectType==null || selectType.length<1)
            return 2;
        int[] storageIds = mtpDevice.getStorageIds();
        if (storageIds == null)
            return 3;
        for (int storageId : storageIds)
            scanObjectsInStorage(mtpDevice, storageId, 0, 0, folder, bMove, selectType, mtpUpdate);
        mtpDevice.close();
        return 0;
    }

    public static int ScanTransfer2(MtpDevice mtpDevice, String folder, boolean bMove, int []selectType, MTPTransferUpdate mtpUpdate)
    {
        if(!(new File(folder).exists()))
            return 1;
        if(selectType==null || selectType.length<1)
            return 2;
        int[] storageIds = mtpDevice.getStorageIds();
        if (storageIds == null)
            return 3;
        for (int storageId : storageIds)
        {
            long []res=countObjectsInStorage2(mtpDevice, storageId, 0, 0, selectType);
            if(mtpUpdate!=null) mtpUpdate.UpdateTotal(res[0],res[1]);
            scanObjectsInStorage2(mtpDevice, storageId, 0, 0, folder, bMove, selectType, mtpUpdate);
        }
        mtpDevice.close();
        return 0;
    }




    public static void LoadList(ArrayList<String> fileList, String fp) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader(new File(fp)));
        String line;
        while ((line = br.readLine()) != null) {
            if(!line.isEmpty())
                fileList.add(line);
        }
        br.close();
    }

    public static void GroupMove(ArrayList<String> fileList, String folder, String newFolder)
    {
        if(fileList.isEmpty())
            return;
        int i=0;
        boolean found=false;
        while(i<fileList.size())
        {
            String filename=fileList.get(i);

            File oldf=new File(folder+"/"+filename);
            if(oldf.exists())
            {

                int segidx=filename.lastIndexOf("/");
                String subfolder=filename.substring(0,segidx);

                if(!found)//build new folder
                {
                    File subf=new File(folder+"/"+subfolder+"/"+newFolder);
                    if(!subf.exists())
                        subf.mkdir();
                    found=true;
                }

                String filename0=filename.substring(segidx,filename.length());

                File newf=new File(folder+"/"+subfolder+"/"+newFolder+filename0);

                oldf.renameTo(newf);

                fileList.remove(i);

            }
            else
            {
                i++;
            }
        }
    }

    public static void GroupMove(String imgFolder, String bkFolder) throws IOException {
        File bkf=new File(bkFolder);
        if(!bkf.exists())
            return;
        File files[] =bkf.listFiles();
        for(File f:files)
        {
            ArrayList<String> filelist=new ArrayList<>();

            LoadList(filelist,f.getAbsolutePath());

            if(filelist.isEmpty())
                continue;

            String fn=f.getName();
            int segidx=fn.lastIndexOf(".");
            String dn=fn.substring(0,segidx);
            GroupMove(filelist,imgFolder,dn);

            if(filelist.isEmpty())
            {
                f.delete();
            }
        }

    }

    public static long[] GetSDCardBytes()
    {
        // TODO Auto-generated method stub
        StatFs stat = new StatFs(Environment.getDataDirectory().getPath());
        //获取每个扇区的大小
        long blockSize = stat.getBlockSizeLong();

        //获取总共有多少扇区
        long totalBlockCount=stat.getBlockCountLong();

        //获取可用扇区数量
        long avaiLabelCount=stat.getAvailableBlocksLong();

        return new long[]{blockSize*avaiLabelCount, blockSize*totalBlockCount};
    }

    public static String SizeStrD(double size)
    {
        if(size<1024)
            return size+"B";
        size/=1024;
        if(size<1024)
            return String.format("%.2f",size)+"KB";
        size/=1024;
        if(size<1024)
            return String.format("%.2f",size)+"MB";
        size/=1024;
        return String.format("%.2f",size)+"GB";
    }

    public static String GetSDCardInfo()
    {
        long []bts= GetSDCardBytes();
        return SizeStrD(bts[0])+"/"+SizeStrD(bts[1]);
    }

    public static long FixInt(int size)
    {
//        Log.v("FixInt","int="+size);
        if(size<0)
            return ((long)size)+(((long)1)<<32);
        return size;
    }

    public static long GetMtpObjectBytes(MtpObjectInfo mtpObjectInfo)
    {
        return FixInt(mtpObjectInfo.getCompressedSize());
    }

    public static String []statusStr=new String[]{"","success","fail","skip"};

    public static String StatusStr(MtpObjectInfo mtpObjectInfo, int status, boolean bMove)
    {
        String filename=mtpObjectInfo.getName();
        long size=GetMtpObjectBytes(mtpObjectInfo);
        String verb=(bMove? "moving":"copying");
        String message=statusStr[status]+" "+verb+"\n"
                +filename+"["+ MTPTransfer.SizeStrD(size)+"]\n"
                +"storage: "+GetSDCardInfo();
        return message;
    }

    public static String StatusStr(String filename, long sizeNow, long sizeTotal, boolean bMove)
    {
        String verb=(bMove? "moving":"copying");
        String message=verb+"\n"
                +filename+"["+ MTPTransfer.SizeStrD(sizeNow)+"/"+ MTPTransfer.SizeStrD(sizeTotal)+"]\n"
                +"storage["+GetSDCardInfo()+"]";
        return message;
    }

}
